package com.stu.io;

import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.file.*;
import java.nio.file.attribute.*;
import java.nio.charset.StandardCharsets;
import java.net.*;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.Future;

/**
 * Java IO和NIO演示
 * 
 * 本类演示了Java IO编程的核心概念，包括：
 * 1. 传统IO（BIO）的使用
 * 2. NIO（New IO）的核心组件
 * 3. 文件操作（读写、复制、移动）
 * 4. 网络编程（Socket、ServerSocket）
 * 5. 序列化和反序列化
 * 6. 字符编码处理
 * 7. IO性能对比
 * 8. NIO.2（AIO）简介
 * 
 * @author 学习者
 * @version 1.0
 * @since JDK 1.8
 */
public class IOAndNIODemo {
    
    // 测试文件路径
    private static final String TEST_DIR = "d:/temp/io-test/";
    private static final String TEST_FILE = TEST_DIR + "test.txt";
    private static final String COPY_FILE = TEST_DIR + "copy.txt";
    private static final String BINARY_FILE = TEST_DIR + "data.dat";
    
    /**
     * 主方法：演示IO和NIO的各个方面
     */
    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        System.out.println("=== Java IO和NIO演示 ===");
        
        try {
            // 创建测试目录
            createTestDirectory();
            
            // 1. 演示传统IO（BIO）
            demonstrateTraditionalIO();
            
            // 2. 演示NIO基础
            demonstrateNIOBasics();
            
            // 3. 演示文件操作
            demonstrateFileOperations();
            
            // 4. 演示字符编码
            demonstrateCharacterEncoding();
            
            // 5. 演示序列化
            demonstrateSerialization();
            
            // 6. 演示网络IO
            demonstrateNetworkIO();
            
            // 7. 演示IO性能对比
            demonstrateIOPerformance();
            
            // 8. 演示NIO.2特性
            demonstrateNIO2Features();
            
        } catch (Exception e) {
            System.err.println("演示过程中发生错误：" + e.getMessage());
            e.printStackTrace();
        } finally {
            // 清理测试文件
            cleanupTestFiles();
        }
    }
    
    /**
     * 创建测试目录
     */
    private static void createTestDirectory() throws IOException {
        Path testDir = Paths.get(TEST_DIR);
        if (!Files.exists(testDir)) {
            Files.createDirectories(testDir);
            System.out.println("创建测试目录：" + TEST_DIR);
        }
    }
    
    /**
     * 演示传统IO（BIO）
     */
    private static void demonstrateTraditionalIO() throws IOException, ClassNotFoundException {
        System.out.println("\n=== 传统IO（BIO）演示 ===");
        
        System.out.println("传统IO特点：");
        System.out.println("1. 阻塞式IO：读写操作会阻塞线程");
        System.out.println("2. 面向流：数据以流的形式处理");
        System.out.println("3. 单向性：输入流和输出流分离");
        System.out.println("4. 简单易用：API设计直观");
        
        // 1. 字节流操作
        System.out.println("\n1. 字节流操作：");
        demonstrateByteStreams();
        
        // 2. 字符流操作
        System.out.println("\n2. 字符流操作：");
        demonstrateCharacterStreams();
        
        // 3. 缓冲流操作
        System.out.println("\n3. 缓冲流操作：");
        demonstrateBufferedStreams();
        
        // 4. 对象流操作
        System.out.println("\n4. 对象流操作：");
        demonstrateObjectStreams();
    }
    
    /**
     * 演示字节流
     */
    private static void demonstrateByteStreams() throws IOException {
        System.out.println("字节流：处理二进制数据，以字节为单位");
        
        String content = "Hello, 字节流测试！\n这是第二行。";
        byte[] data = content.getBytes("UTF-8");
        
        // 写入文件
        System.out.println("使用FileOutputStream写入文件：");
        try (FileOutputStream fos = new FileOutputStream(TEST_FILE)) {
            fos.write(data);
            System.out.println("写入完成，字节数：" + data.length);
        }
        
        // 读取文件
        System.out.println("\n使用FileInputStream读取文件：");
        try (FileInputStream fis = new FileInputStream(TEST_FILE)) {
            byte[] buffer = new byte[1024];
            int bytesRead = fis.read(buffer);
            String readContent = new String(buffer, 0, bytesRead, "UTF-8");
            System.out.println("读取内容：" + readContent);
            System.out.println("读取字节数：" + bytesRead);
        }
        
        System.out.println("\n字节流特点：");
        System.out.println("- 适用于所有类型的文件");
        System.out.println("- 处理二进制数据");
        System.out.println("- 基类：InputStream、OutputStream");
    }
    
    /**
     * 演示字符流
     */
    private static void demonstrateCharacterStreams() throws IOException {
        System.out.println("字符流：处理文本数据，以字符为单位");
        
        String content = "Hello, 字符流测试！\n这是包含中文的文本。\n第三行内容。";
        
        // 写入文件
        System.out.println("使用FileWriter写入文件：");
        try (OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(TEST_FILE), StandardCharsets.UTF_8)) {
            writer.write(content);
            System.out.println("写入完成，字符数：" + content.length());
        }
        
        // 读取文件
        System.out.println("\n使用FileReader读取文件：");
        try (InputStreamReader reader = new InputStreamReader(new FileInputStream(TEST_FILE), StandardCharsets.UTF_8)) {
            char[] buffer = new char[1024];
            int charsRead = reader.read(buffer);
            String readContent = new String(buffer, 0, charsRead);
            System.out.println("读取内容：" + readContent);
            System.out.println("读取字符数：" + charsRead);
        }
        
        // 按行读取
        System.out.println("\n使用BufferedReader按行读取：");
        try (BufferedReader br = new BufferedReader(
                new InputStreamReader(new FileInputStream(TEST_FILE), StandardCharsets.UTF_8))) {
            String line;
            int lineNumber = 1;
            while ((line = br.readLine()) != null) {
                System.out.println("第" + lineNumber + "行：" + line);
                lineNumber++;
            }
        }
        
        System.out.println("\n字符流特点：");
        System.out.println("- 适用于文本文件");
        System.out.println("- 自动处理字符编码");
        System.out.println("- 基类：Reader、Writer");
    }
    
    /**
     * 演示缓冲流
     */
    private static void demonstrateBufferedStreams() throws IOException {
        System.out.println("缓冲流：提供缓冲功能，提高IO性能");
        
        String content = "缓冲流测试内容\n";
        
        // 测试不使用缓冲的性能
        long startTime = System.currentTimeMillis();
        try (FileWriter writer = new FileWriter(TEST_FILE)) {
            for (int i = 0; i < 10000; i++) {
                writer.write(content + i + "\n");
            }
        }
        long unbufferedTime = System.currentTimeMillis() - startTime;
        System.out.println("不使用缓冲写入10000行耗时：" + unbufferedTime + "ms");
        
        // 测试使用缓冲的性能
        startTime = System.currentTimeMillis();
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(COPY_FILE))) {
            for (int i = 0; i < 10000; i++) {
                writer.write(content + i + "\n");
            }
        }
        long bufferedTime = System.currentTimeMillis() - startTime;
        System.out.println("使用缓冲写入10000行耗时：" + bufferedTime + "ms");
        
        System.out.println("性能提升：" + (unbufferedTime > 0 ? 
                          String.format("%.2f", (double) unbufferedTime / bufferedTime) : "显著") + "倍");
        
        // 演示缓冲区大小的影响
        System.out.println("\n演示不同缓冲区大小的影响：");
        testBufferSizes();
        
        System.out.println("\n缓冲流特点：");
        System.out.println("- 内部维护缓冲区，减少系统调用");
        System.out.println("- 显著提高IO性能");
        System.out.println("- 需要手动flush或自动flush");
        System.out.println("- 常用：BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter");
    }
    
    /**
     * 测试不同缓冲区大小的性能
     */
    private static void testBufferSizes() throws IOException {
        int[] bufferSizes = {1024, 4096, 8192, 16384};
        byte[] data = "测试数据\n".getBytes("UTF-8");
        
        for (int bufferSize : bufferSizes) {
            long startTime = System.currentTimeMillis();
            
            try (BufferedOutputStream bos = new BufferedOutputStream(
                    new FileOutputStream(TEST_FILE), bufferSize)) {
                for (int i = 0; i < 50000; i++) {
                    bos.write(data);
                }
            }
            
            long endTime = System.currentTimeMillis();
            System.out.println("缓冲区大小 " + bufferSize + " 字节，耗时：" + (endTime - startTime) + "ms");
        }
    }
    
    /**
     * 演示对象流
     */
    private static void demonstrateObjectStreams() throws IOException, ClassNotFoundException {
        System.out.println("对象流：用于序列化和反序列化对象");
        
        // 创建测试对象
        Person person = new Person("张三", 25, "北京市");
        List<String> hobbies = Arrays.asList("读书", "游泳", "编程");
        
        // 序列化对象
        System.out.println("\n序列化对象到文件：");
        try (ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream(BINARY_FILE))) {
            oos.writeObject(person);
            oos.writeObject(hobbies);
            System.out.println("序列化完成：" + person);
        }
        
        // 反序列化对象
        System.out.println("\n从文件反序列化对象：");
        try (ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream(BINARY_FILE))) {
            Person deserializedPerson = (Person) ois.readObject();
            @SuppressWarnings("unchecked")
            List<String> deserializedHobbies = (List<String>) ois.readObject();
            
            System.out.println("反序列化的Person：" + deserializedPerson);
            System.out.println("反序列化的爱好：" + deserializedHobbies);
        }
        
        System.out.println("\n对象流注意事项：");
        System.out.println("- 类必须实现Serializable接口");
        System.out.println("- transient字段不会被序列化");
        System.out.println("- static字段不会被序列化");
        System.out.println("- 序列化版本号serialVersionUID的重要性");
    }
    
    /**
     * 演示NIO基础
     */
    private static void demonstrateNIOBasics() throws IOException {
        System.out.println("\n=== NIO基础演示 ===");
        
        System.out.println("NIO特点：");
        System.out.println("1. 非阻塞IO：操作不会阻塞线程");
        System.out.println("2. 面向缓冲区：数据读写通过Buffer");
        System.out.println("3. 选择器：一个线程管理多个通道");
        System.out.println("4. 通道：双向数据传输");
        
        // 1. 演示Buffer
        System.out.println("\n1. Buffer演示：");
        demonstrateBuffer();
        
        // 2. 演示Channel
        System.out.println("\n2. Channel演示：");
        demonstrateChannel();
        
        // 3. 演示Selector
        System.out.println("\n3. Selector演示：");
        demonstrateSelector();
    }
    
    /**
     * 演示Buffer
     */
    private static void demonstrateBuffer() {
        System.out.println("Buffer：NIO中的数据容器");
        
        // 创建ByteBuffer
        ByteBuffer buffer = ByteBuffer.allocate(10);
        System.out.println("\n创建容量为10的ByteBuffer：");
        printBufferStatus(buffer, "初始状态");
        
        // 写入数据
        System.out.println("\n写入数据 'Hello'：");
        buffer.put("Hello".getBytes());
        printBufferStatus(buffer, "写入后");
        
        // 切换到读模式
        System.out.println("\n调用flip()切换到读模式：");
        buffer.flip();
        printBufferStatus(buffer, "flip后");
        
        // 读取数据
        System.out.println("\n读取数据：");
        byte[] data = new byte[buffer.remaining()];
        buffer.get(data);
        System.out.println("读取的内容：" + new String(data));
        printBufferStatus(buffer, "读取后");
        
        // 清空缓冲区
        System.out.println("\n调用clear()清空缓冲区：");
        buffer.clear();
        printBufferStatus(buffer, "clear后");
        
        // 演示其他Buffer操作
        System.out.println("\n其他Buffer操作：");
        demonstrateBufferOperations();
    }
    
    /**
     * 打印Buffer状态
     */
    private static void printBufferStatus(ByteBuffer buffer, String stage) {
        System.out.println(stage + " - position: " + buffer.position() + 
                          ", limit: " + buffer.limit() + 
                          ", capacity: " + buffer.capacity() + 
                          ", remaining: " + buffer.remaining());
    }
    
    /**
     * 演示Buffer的其他操作
     */
    private static void demonstrateBufferOperations() {
        ByteBuffer buffer = ByteBuffer.allocate(20);
        
        // mark和reset
        buffer.put("Hello".getBytes());
        buffer.mark(); // 标记当前位置
        buffer.put(" World".getBytes());
        
        System.out.println("mark/reset演示：");
        System.out.println("写入'Hello World'后position: " + buffer.position());
        
        buffer.reset(); // 回到mark位置
        System.out.println("reset后position: " + buffer.position());
        
        // rewind
        buffer.rewind(); // 重置position为0
        System.out.println("rewind后position: " + buffer.position());
        
        // compact
        buffer.position(5);
        buffer.compact(); // 压缩缓冲区
        System.out.println("compact后position: " + buffer.position());
        
        System.out.println("\nBuffer的重要方法：");
        System.out.println("- flip()：切换到读模式");
        System.out.println("- clear()：清空缓冲区");
        System.out.println("- rewind()：重置position为0");
        System.out.println("- mark()：标记当前位置");
        System.out.println("- reset()：回到mark位置");
        System.out.println("- compact()：压缩缓冲区");
    }
    
    /**
     * 演示Channel
     */
    private static void demonstrateChannel() throws IOException {
        System.out.println("Channel：NIO中的数据传输通道");
        
        String content = "NIO Channel测试内容\n这是第二行\n第三行内容";
        
        // 使用FileChannel写入文件
        System.out.println("\n使用FileChannel写入文件：");
        try (FileChannel writeChannel = FileChannel.open(
                Paths.get(TEST_FILE), 
                StandardOpenOption.CREATE, 
                StandardOpenOption.WRITE, 
                StandardOpenOption.TRUNCATE_EXISTING)) {
            
            ByteBuffer buffer = ByteBuffer.wrap(content.getBytes("UTF-8"));
            int bytesWritten = writeChannel.write(buffer);
            System.out.println("写入字节数：" + bytesWritten);
        }
        
        // 使用FileChannel读取文件
        System.out.println("\n使用FileChannel读取文件：");
        try (FileChannel readChannel = FileChannel.open(
                Paths.get(TEST_FILE), StandardOpenOption.READ)) {
            
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            int bytesRead = readChannel.read(buffer);
            
            buffer.flip();
            byte[] data = new byte[buffer.remaining()];
            buffer.get(data);
            
            System.out.println("读取字节数：" + bytesRead);
            System.out.println("读取内容：\n" + new String(data, "UTF-8"));
        }
        
        // 文件复制
        System.out.println("\n使用Channel进行文件复制：");
        copyFileWithChannel();
        
        System.out.println("\nChannel特点：");
        System.out.println("- 双向性：可以同时读写");
        System.out.println("- 非阻塞：支持非阻塞模式");
        System.out.println("- 与Buffer配合：数据传输通过Buffer");
        System.out.println("- 类型：FileChannel、SocketChannel、ServerSocketChannel等");
    }
    
    /**
     * 使用Channel复制文件
     */
    private static void copyFileWithChannel() throws IOException {
        long startTime = System.currentTimeMillis();
        
        try (FileChannel sourceChannel = FileChannel.open(
                Paths.get(TEST_FILE), StandardOpenOption.READ);
             FileChannel targetChannel = FileChannel.open(
                Paths.get(COPY_FILE), 
                StandardOpenOption.CREATE, 
                StandardOpenOption.WRITE, 
                StandardOpenOption.TRUNCATE_EXISTING)) {
            
            // 方法1：使用transferTo（零拷贝）
            long transferred = sourceChannel.transferTo(0, sourceChannel.size(), targetChannel);
            
            long endTime = System.currentTimeMillis();
            System.out.println("复制完成，传输字节数：" + transferred);
            System.out.println("耗时：" + (endTime - startTime) + "ms");
        }
        
        System.out.println("\nChannel复制方法：");
        System.out.println("1. transferTo/transferFrom：零拷贝，高效");
        System.out.println("2. 通过Buffer：传统方式，灵活");
    }
    
    /**
     * 演示Selector
     */
    private static void demonstrateSelector() throws IOException {
        System.out.println("Selector：选择器，用于监控多个通道的IO事件");
        
        System.out.println("\nSelector的作用：");
        System.out.println("1. 单线程管理多个通道");
        System.out.println("2. 监控通道的IO事件");
        System.out.println("3. 实现非阻塞IO");
        System.out.println("4. 提高并发性能");
        
        // 创建Selector
        try (Selector selector = Selector.open()) {
            System.out.println("\n创建Selector成功");
            
            System.out.println("\nSelector支持的事件类型：");
            System.out.println("- SelectionKey.OP_READ：读事件");
            System.out.println("- SelectionKey.OP_WRITE：写事件");
            System.out.println("- SelectionKey.OP_CONNECT：连接事件");
            System.out.println("- SelectionKey.OP_ACCEPT：接受连接事件");
            
            System.out.println("\nSelector使用步骤：");
            System.out.println("1. 创建Selector");
            System.out.println("2. 将Channel注册到Selector");
            System.out.println("3. 调用select()方法等待事件");
            System.out.println("4. 处理就绪的事件");
            
            // 注意：这里只是演示概念，实际的网络编程示例在后面
        }
    }
    
    /**
     * 演示文件操作
     */
    private static void demonstrateFileOperations() throws IOException, InterruptedException {
        System.out.println("\n=== 文件操作演示 ===");
        
        // 1. 文件基本操作
        System.out.println("\n1. 文件基本操作：");
        demonstrateBasicFileOperations();
        
        // 2. 目录操作
        System.out.println("\n2. 目录操作：");
        demonstrateDirectoryOperations();
        
        // 3. 文件属性
        System.out.println("\n3. 文件属性：");
        demonstrateFileAttributes();
        
        // 4. 文件监控
        System.out.println("\n4. 文件监控：");
        demonstrateFileWatching();
    }
    
    /**
     * 演示基本文件操作
     */
    private static void demonstrateBasicFileOperations() throws IOException {
        Path testFile = Paths.get(TEST_FILE);
        Path copyFile = Paths.get(COPY_FILE);
        
        // 创建文件
        if (!Files.exists(testFile)) {
            Files.createFile(testFile);
            System.out.println("创建文件：" + testFile);
        }
        
        // 写入内容
        String content = "文件操作测试内容\n第二行\n第三行";
        Files.write(testFile, content.getBytes("UTF-8"));
        System.out.println("写入文件内容");
        
        // 读取内容
        List<String> lines = Files.readAllLines(testFile, StandardCharsets.UTF_8);
        System.out.println("读取文件内容：");
        for (int i = 0; i < lines.size(); i++) {
            System.out.println("第" + (i + 1) + "行：" + lines.get(i));
        }
        
        // 复制文件
        Files.copy(testFile, copyFile, StandardCopyOption.REPLACE_EXISTING);
        System.out.println("复制文件：" + testFile + " -> " + copyFile);
        
        // 移动文件
        Path moveFile = Paths.get(TEST_DIR + "moved.txt");
        Files.move(copyFile, moveFile, StandardCopyOption.REPLACE_EXISTING);
        System.out.println("移动文件：" + copyFile + " -> " + moveFile);
        
        // 删除文件
        Files.deleteIfExists(moveFile);
        System.out.println("删除文件：" + moveFile);
        
        System.out.println("\nFiles类的常用方法：");
        System.out.println("- createFile/createDirectory：创建文件/目录");
        System.out.println("- copy/move：复制/移动文件");
        System.out.println("- delete/deleteIfExists：删除文件");
        System.out.println("- readAllLines/write：读写文件");
        System.out.println("- exists/isDirectory/isRegularFile：检查文件状态");
    }
    
    /**
     * 演示目录操作
     */
    private static void demonstrateDirectoryOperations() throws IOException {
        Path testDir = Paths.get(TEST_DIR + "subdir");
        
        // 创建目录
        Files.createDirectories(testDir);
        System.out.println("创建目录：" + testDir);
        
        // 在目录中创建文件
        for (int i = 1; i <= 3; i++) {
            Path file = testDir.resolve("file" + i + ".txt");
            Files.write(file, ("文件" + i + "的内容").getBytes("UTF-8"));
        }
        System.out.println("在目录中创建了3个文件");
        
        // 遍历目录
        System.out.println("\n遍历目录内容：");
        try (DirectoryStream<Path> stream = Files.newDirectoryStream(testDir)) {
            for (Path entry : stream) {
                System.out.println("- " + entry.getFileName() + 
                                 " (" + (Files.isDirectory(entry) ? "目录" : "文件") + ")");
            }
        }
        
        // 递归遍历
        System.out.println("\n递归遍历目录树：");
        Files.walk(Paths.get(TEST_DIR))
             .filter(Files::isRegularFile)
             .forEach(path -> System.out.println("文件：" + path));
        
        // 查找文件
        System.out.println("\n查找.txt文件：");
        Files.find(Paths.get(TEST_DIR), 2, 
                   (path, attrs) -> path.toString().endsWith(".txt"))
             .forEach(path -> System.out.println("找到：" + path));
        
        System.out.println("\n目录操作方法：");
        System.out.println("- newDirectoryStream：遍历目录");
        System.out.println("- walk：递归遍历目录树");
        System.out.println("- find：查找文件");
        System.out.println("- list：列出目录内容");
    }
    
    /**
     * 演示文件属性
     */
    private static void demonstrateFileAttributes() throws IOException {
        Path testFile = Paths.get(TEST_FILE);
        
        // 基本属性
        System.out.println("文件基本属性：");
        System.out.println("- 文件名：" + testFile.getFileName());
        System.out.println("- 绝对路径：" + testFile.toAbsolutePath());
        System.out.println("- 父目录：" + testFile.getParent());
        System.out.println("- 是否存在：" + Files.exists(testFile));
        System.out.println("- 是否为文件：" + Files.isRegularFile(testFile));
        System.out.println("- 是否为目录：" + Files.isDirectory(testFile));
        System.out.println("- 是否可读：" + Files.isReadable(testFile));
        System.out.println("- 是否可写：" + Files.isWritable(testFile));
        System.out.println("- 是否可执行：" + Files.isExecutable(testFile));
        
        // 详细属性
        System.out.println("\n文件详细属性：");
        BasicFileAttributes attrs = Files.readAttributes(testFile, BasicFileAttributes.class);
        System.out.println("- 文件大小：" + attrs.size() + " 字节");
        System.out.println("- 创建时间：" + attrs.creationTime());
        System.out.println("- 最后修改时间：" + attrs.lastModifiedTime());
        System.out.println("- 最后访问时间：" + attrs.lastAccessTime());
        System.out.println("- 是否为目录：" + attrs.isDirectory());
        System.out.println("- 是否为常规文件：" + attrs.isRegularFile());
        System.out.println("- 是否为符号链接：" + attrs.isSymbolicLink());
        
        System.out.println("\n文件属性类型：");
        System.out.println("- BasicFileAttributes：基本属性");
        System.out.println("- DosFileAttributes：DOS文件系统属性");
        System.out.println("- PosixFileAttributes：POSIX文件系统属性");
    }
    
    /**
     * 演示文件监控
     */
    private static void demonstrateFileWatching() throws IOException, InterruptedException {
        System.out.println("文件监控：监控目录中文件的变化");
        
        Path watchDir = Paths.get(TEST_DIR);
        
        // 创建WatchService
        try (WatchService watchService = FileSystems.getDefault().newWatchService()) {
            
            // 注册监控事件
            watchDir.register(watchService, 
                             StandardWatchEventKinds.ENTRY_CREATE,
                             StandardWatchEventKinds.ENTRY_MODIFY,
                             StandardWatchEventKinds.ENTRY_DELETE);
            
            System.out.println("开始监控目录：" + watchDir);
            System.out.println("将在2秒后创建一个测试文件...");
            
            // 在另一个线程中创建文件来触发事件
            new Thread(() -> {
                try {
                    Thread.sleep(2000);
                    Path testFile = watchDir.resolve("watch-test.txt");
                    Files.write(testFile, "监控测试".getBytes("UTF-8"));
                    
                    Thread.sleep(1000);
                    Files.write(testFile, "修改内容".getBytes("UTF-8"));
                    
                    Thread.sleep(1000);
                    Files.deleteIfExists(testFile);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }).start();
            
            // 监控事件（最多等待5秒）
            long endTime = System.currentTimeMillis() + 5000;
            while (System.currentTimeMillis() < endTime) {
                WatchKey key = watchService.poll(1, TimeUnit.SECONDS);
                if (key != null) {
                    for (WatchEvent<?> event : key.pollEvents()) {
                        WatchEvent.Kind<?> kind = event.kind();
                        Path fileName = (Path) event.context();
                        
                        System.out.println("检测到事件：" + kind + " - " + fileName);
                    }
                    
                    // 重置key，继续监控
                    boolean valid = key.reset();
                    if (!valid) {
                        break;
                    }
                }
            }
        }
        
        System.out.println("\nWatchService特点：");
        System.out.println("- 监控目录变化");
        System.out.println("- 支持创建、修改、删除事件");
        System.out.println("- 异步通知机制");
        System.out.println("- 适用于文件同步、热部署等场景");
    }
    
    /**
     * 演示字符编码
     */
    private static void demonstrateCharacterEncoding() throws IOException {
        System.out.println("\n=== 字符编码演示 ===");
        
        String text = "Hello, 世界！这是编码测试。";
        
        System.out.println("原始文本：" + text);
        System.out.println("\n不同编码的字节表示：");
        
        // 不同编码的字节数组
        Map<String, byte[]> encodings = new HashMap<>();
        encodings.put("UTF-8", text.getBytes(StandardCharsets.UTF_8));
        encodings.put("UTF-16", text.getBytes(StandardCharsets.UTF_16));
        encodings.put("GBK", text.getBytes("GBK"));
        encodings.put("ISO-8859-1", text.getBytes(StandardCharsets.ISO_8859_1));
        
        for (Map.Entry<String, byte[]> entry : encodings.entrySet()) {
            String encoding = entry.getKey();
            byte[] bytes = entry.getValue();
            System.out.println(encoding + "：" + bytes.length + " 字节");
        }
        
        // 编码转换
        System.out.println("\n编码转换演示：");
        demonstrateEncodingConversion(text);
        
        // 文件编码
        System.out.println("\n文件编码演示：");
        demonstrateFileEncoding(text);
        
        System.out.println("\n编码注意事项：");
        System.out.println("1. 统一使用UTF-8编码");
        System.out.println("2. 读写文件时指定编码");
        System.out.println("3. 网络传输时注意编码");
        System.out.println("4. 避免编码转换丢失数据");
    }
    
    /**
     * 演示编码转换
     */
    private static void demonstrateEncodingConversion(String text) throws UnsupportedEncodingException {
        // UTF-8 -> GBK -> UTF-8
        byte[] utf8Bytes = text.getBytes("UTF-8");
        String gbkString = new String(utf8Bytes, "UTF-8");
        byte[] gbkBytes = gbkString.getBytes("GBK");
        String resultString = new String(gbkBytes, "GBK");
        
        System.out.println("原始：" + text);
        System.out.println("转换后：" + resultString);
        System.out.println("是否相等：" + text.equals(resultString));
        
        // 错误的编码转换
        System.out.println("\n错误的编码转换示例：");
        byte[] utf8 = text.getBytes("UTF-8");
        String wrongDecode = new String(utf8, "GBK"); // 用错误的编码解码
        System.out.println("错误解码结果：" + wrongDecode);
    }
    
    /**
     * 演示文件编码
     */
    private static void demonstrateFileEncoding(String text) throws IOException {
        Path utf8File = Paths.get(TEST_DIR + "utf8.txt");
        Path gbkFile = Paths.get(TEST_DIR + "gbk.txt");
        
        // 以不同编码写入文件
        Files.write(utf8File, text.getBytes("UTF-8"));
        Files.write(gbkFile, text.getBytes("GBK"));
        
        System.out.println("UTF-8文件大小：" + Files.size(utf8File) + " 字节");
        System.out.println("GBK文件大小：" + Files.size(gbkFile) + " 字节");
        
        // 以正确编码读取
        String utf8Content = new String(Files.readAllBytes(utf8File), "UTF-8");
        String gbkContent = new String(Files.readAllBytes(gbkFile), "GBK");
        
        System.out.println("UTF-8读取：" + utf8Content);
        System.out.println("GBK读取：" + gbkContent);
        
        // 清理文件
        Files.deleteIfExists(utf8File);
        Files.deleteIfExists(gbkFile);
    }
    
    /**
     * 演示序列化
     */
    private static void demonstrateSerialization() throws IOException, ClassNotFoundException {
        System.out.println("\n=== 序列化演示 ===");
        
        System.out.println("序列化：将对象转换为字节流");
        System.out.println("反序列化：将字节流转换为对象");
        
        // 创建测试对象
        Person person = new Person("李四", 30, "上海市");
        
        // 序列化到字节数组
        System.out.println("\n序列化到字节数组：");
        byte[] serializedData = serializeToBytes(person);
        System.out.println("序列化后字节数组长度：" + serializedData.length);
        
        // 从字节数组反序列化
        System.out.println("\n从字节数组反序列化：");
        Person deserializedPerson = deserializeFromBytes(serializedData);
        System.out.println("反序列化结果：" + deserializedPerson);
        
        // 演示序列化版本控制
        System.out.println("\n序列化版本控制：");
        demonstrateSerializationVersioning();
        
        System.out.println("\n序列化最佳实践：");
        System.out.println("1. 实现Serializable接口");
        System.out.println("2. 定义serialVersionUID");
        System.out.println("3. 使用transient关键字排除敏感字段");
        System.out.println("4. 考虑使用Externalizable接口自定义序列化");
        System.out.println("5. 注意序列化性能和安全性");
    }
    
    /**
     * 序列化对象到字节数组
     */
    private static byte[] serializeToBytes(Object obj) throws IOException {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
             ObjectOutputStream oos = new ObjectOutputStream(baos)) {
            oos.writeObject(obj);
            return baos.toByteArray();
        }
    }
    
    /**
     * 从字节数组反序列化对象
     */
    @SuppressWarnings("unchecked")
    private static <T> T deserializeFromBytes(byte[] data) throws IOException, ClassNotFoundException {
        try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
             ObjectInputStream ois = new ObjectInputStream(bais)) {
            return (T) ois.readObject();
        }
    }
    
    /**
     * 演示序列化版本控制
     */
    private static void demonstrateSerializationVersioning() {
        System.out.println("serialVersionUID的作用：");
        System.out.println("1. 版本控制：确保序列化兼容性");
        System.out.println("2. 安全性：防止恶意序列化攻击");
        System.out.println("3. 性能：避免自动生成版本号的开销");
        
        System.out.println("\n版本兼容性规则：");
        System.out.println("- 相同serialVersionUID：兼容");
        System.out.println("- 不同serialVersionUID：不兼容，抛出异常");
        System.out.println("- 未定义serialVersionUID：自动生成，易变");
    }
    
    /**
     * 演示网络IO
     */
    private static void demonstrateNetworkIO() {
        System.out.println("\n=== 网络IO演示 ===");
        
        System.out.println("网络IO类型：");
        System.out.println("1. BIO：阻塞式IO，一个连接一个线程");
        System.out.println("2. NIO：非阻塞式IO，一个线程处理多个连接");
        System.out.println("3. AIO：异步IO，基于回调机制");
        
        // 演示简单的Socket通信
        System.out.println("\n演示Socket通信：");
        demonstrateSocketCommunication();
        
        // 演示NIO网络编程
        System.out.println("\n演示NIO网络编程：");
        demonstrateNIONetworking();
    }
    
    /**
     * 演示Socket通信
     */
    private static void demonstrateSocketCommunication() {
        final int PORT = 8888;
        
        // 启动服务器
        Thread serverThread = new Thread(() -> {
            try (ServerSocket serverSocket = new ServerSocket(PORT)) {
                System.out.println("服务器启动，监听端口：" + PORT);
                
                try (Socket clientSocket = serverSocket.accept();
                     BufferedReader in = new BufferedReader(
                         new InputStreamReader(clientSocket.getInputStream()));
                     PrintWriter out = new PrintWriter(
                         clientSocket.getOutputStream(), true)) {
                    
                    System.out.println("客户端连接：" + clientSocket.getRemoteSocketAddress());
                    
                    String inputLine;
                    while ((inputLine = in.readLine()) != null) {
                        System.out.println("服务器收到：" + inputLine);
                        out.println("Echo: " + inputLine);
                        
                        if ("bye".equalsIgnoreCase(inputLine)) {
                            break;
                        }
                    }
                }
            } catch (IOException e) {
                System.err.println("服务器错误：" + e.getMessage());
            }
        });
        
        serverThread.start();
        
        // 等待服务器启动
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        // 启动客户端
        try (Socket socket = new Socket("localhost", PORT);
             PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
             BufferedReader in = new BufferedReader(
                 new InputStreamReader(socket.getInputStream()))) {
            
            System.out.println("客户端连接到服务器");
            
            // 发送消息
            String[] messages = {"Hello", "World", "Java Socket", "bye"};
            for (String message : messages) {
                out.println(message);
                String response = in.readLine();
                System.out.println("客户端收到：" + response);
            }
            
        } catch (IOException e) {
            System.err.println("客户端错误：" + e.getMessage());
        }
        
        // 等待服务器线程结束
        try {
            serverThread.join(5000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        System.out.println("\nSocket通信特点：");
        System.out.println("- 基于TCP协议，可靠传输");
        System.out.println("- 阻塞式IO，简单易用");
        System.out.println("- 适用于连接数较少的场景");
    }
    
    /**
     * 演示NIO网络编程
     */
    private static void demonstrateNIONetworking() {
        System.out.println("NIO网络编程特点：");
        System.out.println("1. 非阻塞：不会阻塞线程");
        System.out.println("2. 选择器：一个线程管理多个连接");
        System.out.println("3. 缓冲区：数据通过Buffer传输");
        System.out.println("4. 事件驱动：基于事件处理");
        
        System.out.println("\nNIO网络编程步骤：");
        System.out.println("1. 创建Selector");
        System.out.println("2. 创建ServerSocketChannel");
        System.out.println("3. 设置非阻塞模式");
        System.out.println("4. 注册到Selector");
        System.out.println("5. 循环处理事件");
        
        // 由于NIO网络编程比较复杂，这里只展示概念
        // 实际应用中通常使用Netty等框架
        System.out.println("\n实际开发建议：");
        System.out.println("- 使用Netty框架：简化NIO编程");
        System.out.println("- 使用Spring Boot：集成Web服务器");
        System.out.println("- 考虑WebSocket：实时通信");
    }
    
    /**
     * 演示IO性能对比
     */
    private static void demonstrateIOPerformance() throws IOException {
        System.out.println("\n=== IO性能对比 ===");
        
        int fileSize = 1024 * 1024; // 1MB
        byte[] data = new byte[fileSize];
        Arrays.fill(data, (byte) 'A');
        
        System.out.println("测试文件大小：" + fileSize + " 字节");
        
        // 1. 传统IO性能测试
        System.out.println("\n1. 传统IO性能测试：");
        long bioTime = testBIOPerformance(data);
        System.out.println("传统IO耗时：" + bioTime + "ms");
        
        // 2. NIO性能测试
        System.out.println("\n2. NIO性能测试：");
        long nioTime = testNIOPerformance(data);
        System.out.println("NIO耗时：" + nioTime + "ms");
        
        // 3. 缓冲IO性能测试
        System.out.println("\n3. 缓冲IO性能测试：");
        long bufferedTime = testBufferedIOPerformance(data);
        System.out.println("缓冲IO耗时：" + bufferedTime + "ms");
        
        // 性能对比
        System.out.println("\n性能对比：");
        System.out.println("传统IO：" + bioTime + "ms");
        System.out.println("NIO：" + nioTime + "ms (" + 
                          String.format("%.2f", (double) bioTime / nioTime) + "倍)");
        System.out.println("缓冲IO：" + bufferedTime + "ms (" + 
                          String.format("%.2f", (double) bioTime / bufferedTime) + "倍)");
        
        System.out.println("\n性能优化建议：");
        System.out.println("1. 使用缓冲流提高性能");
        System.out.println("2. 大文件操作使用NIO");
        System.out.println("3. 合理设置缓冲区大小");
        System.out.println("4. 避免频繁的小IO操作");
    }
    
    /**
     * 测试传统IO性能
     */
    private static long testBIOPerformance(byte[] data) throws IOException {
        Path testFile = Paths.get(TEST_DIR + "bio-test.dat");
        
        long startTime = System.currentTimeMillis();
        
        // 写入
        try (FileOutputStream fos = new FileOutputStream(testFile.toFile())) {
            fos.write(data);
        }
        
        // 读取
        try (FileInputStream fis = new FileInputStream(testFile.toFile())) {
            byte[] buffer = new byte[1024];
            while (fis.read(buffer) != -1) {
                // 读取数据
            }
        }
        
        long endTime = System.currentTimeMillis();
        
        Files.deleteIfExists(testFile);
        return endTime - startTime;
    }
    
    /**
     * 测试NIO性能
     */
    private static long testNIOPerformance(byte[] data) throws IOException {
        Path testFile = Paths.get(TEST_DIR + "nio-test.dat");
        
        long startTime = System.currentTimeMillis();
        
        // 写入
        try (FileChannel channel = FileChannel.open(testFile, 
                StandardOpenOption.CREATE, 
                StandardOpenOption.WRITE, 
                StandardOpenOption.TRUNCATE_EXISTING)) {
            ByteBuffer buffer = ByteBuffer.wrap(data);
            channel.write(buffer);
        }
        
        // 读取
        try (FileChannel channel = FileChannel.open(testFile, StandardOpenOption.READ)) {
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            while (channel.read(buffer) != -1) {
                buffer.clear();
            }
        }
        
        long endTime = System.currentTimeMillis();
        
        Files.deleteIfExists(testFile);
        return endTime - startTime;
    }
    
    /**
     * 测试缓冲IO性能
     */
    private static long testBufferedIOPerformance(byte[] data) throws IOException {
        Path testFile = Paths.get(TEST_DIR + "buffered-test.dat");
        
        long startTime = System.currentTimeMillis();
        
        // 写入
        try (BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream(testFile.toFile()))) {
            bos.write(data);
        }
        
        // 读取
        try (BufferedInputStream bis = new BufferedInputStream(
                new FileInputStream(testFile.toFile()))) {
            byte[] buffer = new byte[1024];
            while (bis.read(buffer) != -1) {
                // 读取数据
            }
        }
        
        long endTime = System.currentTimeMillis();
        
        Files.deleteIfExists(testFile);
        return endTime - startTime;
    }
    
    /**
     * 演示NIO.2特性
     */
    private static void demonstrateNIO2Features() throws IOException, InterruptedException {
        System.out.println("\n=== NIO.2特性演示 ===");
        
        System.out.println("NIO.2（Java 7引入）新特性：");
        System.out.println("1. Path和Paths：更好的文件路径处理");
        System.out.println("2. Files类：丰富的文件操作方法");
        System.out.println("3. WatchService：文件系统监控");
        System.out.println("4. 异步IO：AsynchronousFileChannel");
        System.out.println("5. 文件属性：更详细的文件信息");
        
        // Path操作
        System.out.println("\nPath操作演示：");
        demonstratePathOperations();
        
        // 异步IO
        System.out.println("\n异步IO演示：");
        demonstrateAsynchronousIO();
        
        System.out.println("\nNIO.2优势：");
        System.out.println("1. 更简洁的API");
        System.out.println("2. 更好的性能");
        System.out.println("3. 更丰富的功能");
        System.out.println("4. 更好的跨平台支持");
    }
    
    /**
     * 演示Path操作
     */
    private static void demonstratePathOperations() {
        System.out.println("Path操作：更灵活的路径处理");
        
        Path path = Paths.get(TEST_DIR, "subdir", "file.txt");
        
        System.out.println("路径信息：");
        System.out.println("- 完整路径：" + path);
        System.out.println("- 绝对路径：" + path.toAbsolutePath());
        System.out.println("- 文件名：" + path.getFileName());
        System.out.println("- 父目录：" + path.getParent());
        System.out.println("- 根目录：" + path.getRoot());
        System.out.println("- 路径元素数量：" + path.getNameCount());
        
        // 路径操作
        System.out.println("\n路径操作：");
        Path parent = path.getParent();
        Path resolved = parent.resolve("another-file.txt");
        Path relativized = path.relativize(Paths.get(TEST_DIR + "other.txt"));
        
        System.out.println("- 解析路径：" + resolved);
        System.out.println("- 相对路径：" + relativized);
        
        // 路径比较
        System.out.println("\n路径比较：");
        Path path1 = Paths.get("file.txt");
        Path path2 = Paths.get("./file.txt");
        System.out.println("路径相等：" + path1.equals(path2));
        System.out.println("标准化后相等：" + path1.normalize().equals(path2.normalize()));
    }
    
    /**
     * 演示异步IO
     */
    private static void demonstrateAsynchronousIO() throws IOException {
        System.out.println("异步IO：非阻塞的文件操作");
        
        Path asyncFile = Paths.get(TEST_DIR + "async-test.txt");
        String content = "异步IO测试内容\n这是异步写入的数据";
        
        try (AsynchronousFileChannel channel = AsynchronousFileChannel.open(
                asyncFile, 
                StandardOpenOption.CREATE, 
                StandardOpenOption.WRITE, 
                StandardOpenOption.READ)) {
            
            // 异步写入
            System.out.println("\n异步写入文件：");
            ByteBuffer writeBuffer = ByteBuffer.wrap(content.getBytes("UTF-8"));
            
            Future<Integer> writeResult = channel.write(writeBuffer, 0);
            
            // 等待写入完成
            try {
                Integer bytesWritten = writeResult.get();
                System.out.println("异步写入完成，字节数：" + bytesWritten);
            } catch (Exception e) {
                System.err.println("异步写入失败：" + e.getMessage());
            }
            
            // 异步读取
            System.out.println("\n异步读取文件：");
            ByteBuffer readBuffer = ByteBuffer.allocate(1024);
            
            Future<Integer> readResult = channel.read(readBuffer, 0);
            
            // 等待读取完成
            try {
                Integer bytesRead = readResult.get();
                readBuffer.flip();
                
                byte[] data = new byte[readBuffer.remaining()];
                readBuffer.get(data);
                
                System.out.println("异步读取完成，字节数：" + bytesRead);
                System.out.println("读取内容：" + new String(data, "UTF-8"));
            } catch (Exception e) {
                System.err.println("异步读取失败：" + e.getMessage());
            }
        }
        
        // 清理文件
        Files.deleteIfExists(asyncFile);
        
        System.out.println("\n异步IO特点：");
        System.out.println("1. 非阻塞：不会阻塞调用线程");
        System.out.println("2. 回调机制：支持CompletionHandler");
        System.out.println("3. Future模式：支持Future获取结果");
        System.out.println("4. 高性能：适用于高并发场景");
    }
    
    /**
     * 清理测试文件
     */
    private static void cleanupTestFiles() {
        try {
            // 删除测试目录及其内容
            if (Files.exists(Paths.get(TEST_DIR))) {
                Files.walk(Paths.get(TEST_DIR))
                     .sorted((a, b) -> b.compareTo(a)) // 先删除文件，后删除目录
                     .forEach(path -> {
                         try {
                             Files.deleteIfExists(path);
                         } catch (IOException e) {
                             System.err.println("删除文件失败：" + path + " - " + e.getMessage());
                         }
                     });
            }
            System.out.println("\n清理测试文件完成");
        } catch (IOException e) {
            System.err.println("清理测试文件失败：" + e.getMessage());
        }
    }
}

/**
 * 测试用的Person类
 * 实现Serializable接口支持序列化
 */
class Person implements Serializable {
    
    // 序列化版本号，用于版本控制
    private static final long serialVersionUID = 1L;
    
    private String name;
    private int age;
    private String address;
    
    // transient字段不会被序列化
    private transient String password = "secret";
    
    /**
     * 构造方法
     */
    public Person(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }
    
    // Getter和Setter方法
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
    
    public String getAddress() {
        return address;
    }
    
    public void setAddress(String address) {
        this.address = address;
    }
    
    public String getPassword() {
        return password;
    }
    
    public void setPassword(String password) {
        this.password = password;
    }
    
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        
        Person person = (Person) obj;
        return age == person.age &&
               Objects.equals(name, person.name) &&
               Objects.equals(address, person.address);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(name, age, address);
    }
}